 /*******************************************************************************
  * Copyright (c) 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/

 package org.eclipse.ui.internal.cheatsheets.composite.model;

 import java.util.HashSet ;
 import java.util.Iterator ;
 import java.util.Set ;

 import org.eclipse.ui.internal.provisional.cheatsheets.ICompositeCheatSheetTask;

 public class BlockedTaskFinder {
     
     private Set stateChangedTasks;
     private Set impactedTasks;
     /**
      * Find which tasks have either become blocked or unblocked so that they
      * can be added to the list of change events.
      * @param stateChangedTasks The set of tasks which has changed
      * @return The set of tasks which have become blocked or unblocked by the
      * change of state and were not in the original set. The algorithm will sometimes add tasks to
      * the result set which were not actually impacted but this is not a major problem
      * since it only means that extra events get sent to the explorer. For updates other
      * than resets the number of extra events is very low.
      *
      * This takes several steps.
      * <li> If a group is completed, skipped or reset add any non-started children.
      * <li> Determine all successors of tasks whose state has changed that are not in the change set
      * <li> Add the successor and its children to the list if not started
      */
     
     public Set findBlockedTaskChanges(Set stateChangedTasks) {
         this.stateChangedTasks = stateChangedTasks;
         impactedTasks = new HashSet ();
         visitChangedTasks();
         findSuccesors();
         return impactedTasks;
     }

     private void visitChangedTasks() {
         for (Iterator iter = stateChangedTasks.iterator(); iter.hasNext(); ) {
             final ICompositeCheatSheetTask nextTask = (ICompositeCheatSheetTask)iter.next();
             if (nextTask.getState() != ICompositeCheatSheetTask.IN_PROGRESS) {
                 findUnstartedChildren(nextTask);
             }
         }
     }

     /*
      * Look for children which we have not seen elsewhere and if they are not started
      * add them to the list of impacted tasks.
      */
     private void findUnstartedChildren(ICompositeCheatSheetTask task) {
         ICompositeCheatSheetTask[] children = task.getSubtasks();
         for (int i = 0; i < children.length; i++) {
             ICompositeCheatSheetTask nextChild = children[i];
             // Ignore if this task has been seen before
 if ((!stateChangedTasks.contains(nextChild)) && !impactedTasks.contains(nextChild)) {
                 if (nextChild.getState() == ICompositeCheatSheetTask.NOT_STARTED) {
                    impactedTasks.add(nextChild);
                 }
                 findUnstartedChildren(nextChild);
             }
         }
     }

     private void findSuccesors() {
         for (Iterator iter = stateChangedTasks.iterator(); iter.hasNext(); ) {
             final AbstractTask nextTask = (AbstractTask)iter.next();
             ICompositeCheatSheetTask[] successors = nextTask.getSuccessorTasks();
             for (int i = 0; i < successors.length; i++) {
                 ICompositeCheatSheetTask nextSuccessor = successors[i];
                 if (nextSuccessor.getState() == ICompositeCheatSheetTask.NOT_STARTED) {
                     impactedTasks.add(nextSuccessor);
                 }
                 findUnstartedChildren(nextSuccessor);
             }
         }
     }

 }

